﻿using System;
using ParserGenerator.GrammarConstruction;
using ParserGenerator.SyntacticAnalysis;

namespace ParserGenerator.GrammarAnalysis
{
    [Serializable]
    internal sealed class UserRuleTokenCollector : IDefinedTokenCollector
    {
        private readonly GrammarTerminalTable _tokens;

        public UserRuleTokenCollector(GrammarTerminalTable tokens)
        {
            if (tokens == null)
                throw new ArgumentNullException(nameof(tokens));
            _tokens = tokens;
        }

        public void ProcessNameReferenceExpression(NameReferenceExpression n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            GrammarTerminalSymbol token = _tokens.LookupNamed(n.Name);
            _tokens.AddUserRuleToken(token);
        }

        public void ProcessQuoteStringExpression(QuoteStringExpression n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            StringLiteral c = n.Value;
            GrammarTerminalSymbol token = _tokens.LookupLiteral(c.Value, c.Context);
            _tokens.AddUserRuleToken(token);
        }

        public void ProcessYieldExpression(YieldExpression n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (n.Value != null)
            {
                if (n.Value.IsNameReference)
                    ProcessNameReferenceExpression(n.Value.AsNameReference);
                else if (n.Value.IsQuoteString)
                    ProcessQuoteStringExpression(n.Value.AsQuoteString);
            }
        }

        public void ProcessExpression(Expression n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (n.IsYield)
                ProcessYieldExpression(n.AsYield);
        }

        public void ProcessSemanticAction(SemanticAction n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            n.AcceptDefinedTokenCollector(this);
        }

        public void ProcessFastSemanticAction(FastSemanticAction n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (n.Value.IsNameReference)
                ProcessNameReferenceExpression(n.Value.AsNameReference);
            else if (n.Value.IsQuoteString)
                ProcessQuoteStringExpression(n.Value.AsQuoteString);
            else
                ProcessExpression(n.Value);
        }

        public void ProcessFullSemanticAction(FullSemanticAction n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Actions);
        }

        public void ProcessStatement(Statement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            n.AcceptDefinedTokenCollector(this);
        }

        public void ProcessPassStatement(PassStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessBreakStatement(BreakStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessContinueStatement(ContinueStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessReturnStatement(ReturnStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessThrowStatement(ThrowStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessAssertStatement(AssertStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessDeleteStatement(DeleteStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessGlobalStatement(GlobalStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessNonlocalStatement(NonlocalStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessImportStatement(ImportStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessFromImportStatement(FromImportStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessFromImportAllStatement(FromImportAllStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessLetStatement(LetStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessVarStatement(VarStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessConstStatement(ConstStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessExprStatement(ExprStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessExpression(n.Value);
        }

        public void ProcessAssignStatement(AssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessAnnotatedAssignStatement(AnnotatedAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessAddAssignStatement(AddAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessSubtractAssignStatement(SubtractAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessMultiplyAssignStatement(MultiplyAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessMatrixMultiplyAssignStatement(MatrixMultiplyAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessFloorDivideAssignStatement(FloorDivideAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessDivideAssignStatement(DivideAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessModuloAssignStatement(ModuloAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessPowerAssignStatement(PowerAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessLeftShiftAssignStatement(LeftShiftAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessRightShiftAssignStatement(RightShiftAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessUnsignedRightShiftAssignStatement(UnsignedRightShiftAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessBitwiseAndAssignStatement(BitwiseAndAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessBitwiseXorAssignStatement(BitwiseXorAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessBitwiseOrAssignStatement(BitwiseOrAssignStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessSequenceStatement(SequenceStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            foreach (Statement item in n.Items)
                ProcessStatement(item);
        }

        public void ProcessSimpleStatement(SimpleStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Body);
        }

        public void ProcessBlockStatement(BlockStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            foreach (Statement item in n.Body)
                ProcessStatement(item);
        }

        public void ProcessSuiteStatement(SuiteStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Body);
        }

        public void ProcessWithStatement(WithStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Body);
        }

        public void ProcessForStatement(ForStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Body);
            if (n.OrElse != null)
                ProcessStatement(n.OrElse);
        }

        public void ProcessWhileStatement(WhileStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Body);
            if (n.OrElse != null)
                ProcessStatement(n.OrElse);
        }

        public void ProcessIfStatement(IfStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessTryStatement(TryStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            ProcessStatement(n.Body);
            foreach (ExceptionHandler handler in n.Handlers)
                ProcessStatement(handler.Body);
            if (n.OrElse != null)
                ProcessStatement(n.OrElse);
            if (n.FinalBody != null)
                ProcessStatement(n.FinalBody);
        }

        public void ProcessSwitchStatement(SwitchStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            foreach (SwitchCaseClause clause in n.Clauses)
                ProcessStatement(clause.Body);
            if (n.DefaultActions != null)
                ProcessStatement(n.DefaultActions);
        }

        public void ProcessFunctionStatement(FunctionStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessClassStatement(ClassStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessGrammarStatement(GrammarStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessEnumTypeStatement(EnumTypeStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessStructTypeStatement(StructTypeStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessUnionTypeStatement(UnionTypeStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessVisitorTypeStatement(VisitorTypeStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessInterfaceTypeStatement(InterfaceTypeStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessClassTypeStatement(ClassTypeStatement n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
        }

        public void ProcessLexicalStartDeclarator(LexicalStartDeclarator n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            foreach (LexicalRuleDeclarator rule in n.Rules)
                if (rule.Action != null)
                    ProcessSemanticAction(rule.Action);
            if (n.DefaultAction != null)
                ProcessSemanticAction(n.DefaultAction);
        }

        public void ProcessLexicalDeclaration(LexicalDeclaration n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            foreach (LexicalDeclarator item in n.Declarators)
                if (item.IsStart)
                    ProcessLexicalStartDeclarator(item.AsStart.Declarator);
        }
    }
}
